The LFN Library for Clipper
     
     The LFN Library for Clipper is a set of functions for handling long
     file names. It is an original work by Klas Engwall and placed in the
     public domain. Source code is included, so you can change anything
     you want to make it better suit your needs. The LIB files included in
     the distribution are compiled with Clipper 5.2e, so you may need to
     recompile the source code if your environment is different.
     
 Background
     
     Back in 1997 Ian "DrDebug" Day of Dark Black Software embarked on
     a project aiming at providing LFN support in Clipper. He intended
     to make it a patch which would allow normal usage of Clipper's
     existing file handling functions while getting the added LFN
     functionality.
     
     Ian's approach was much more ambitious than my approach in this
     library, and his knowledge of the inner workings of Clipper and DOS
     is on an entirely different level than mine. So if Clipper had been
     more cooperative, his patch would have solved the LFN problem (except
     on NT4, which has no LFN support at all in the VDM) in a better way
     than I can offer.
     
     But unfortunately Ian discovered that Clipper truncates file names
     after 16 characters, so in spite of all his work and clever solutions
     there was still a serious problem caused by Clipper itself. And
     judging from the readme files included in the last available beta
     version of his library (version 0.05), that was the reason he stopped
     development.
     
     There have been many questions about LFN support on comp.lang.clipper
     in the years since, but as far as I know there is no other solution
     than Ian's DBLFN library publicly available. Until now.
     
 So what am I doing here?
     
     Well, I found that there was need for some kind of solution that
     would give Clipper programmers access to file names longer than the
     16 total characters that Clipper allows the users of Ian's DBLFN
     library. So I decided to look into it and see what could be done.
     And although my solution is not nearly as elegant as Ian's would
     have been if Clipper had let him do what he intended, it does handle
     file names of any length  -  within the OS limits, of course.
     
     I spent a couple of weeks in June/July 2002 working on this project,
     and this is what I came up with. I call it the LFN Library. It has
     functions for creating, opening, renaming and erasing files with long
     names, for creating, renaming and erasing directories, for changing
     the current directory, for searching directories and a few other
     things. After the relase of the first beta version (Rev 0.90) on July
     31, I decided to migrate some routines to assembly in order to speed
     up executuion and also to try to add support for the extended get/set
     attributes DOS services (getting and setting file date, time and
     attributes). This support was added in Rev 0.91, and it was further
     extended in Rev 0.92, which also included a function for copying an
     existing file with a long file name to a new file. Rev 1.00 now adds
     a little more speed to that function by moving the read/write loop to
     assembly.
     
     The library also comes with a complete demo application. It is included
     in the LIB file for convenience. Just call it with "LFNdemo()" from
     your application and you will se what the LFN Library can do. LFNdemo()
     will restore the screen and the program settings when it returns control
     to your application. 
     
     The LFN Library has no direct support for using long file names with
     "Clipper's own" files although I think it would be possible using a
     bit of trickery in combination with the normal file handling routines
     (converting long and short file names back and forth as needed). I
     have focused entirely on "external" files because I feel that that
     is the area where the greatest need for LFN support is  -  in communi-
     cating with other applications that use long file names.
     
 How is it done and how does it work?
     
     The LFN Library uses the 71xx DOS services under INT 21h that were
     introduced with Windows 95. For each function in the LFN Library,
     the underlying DOS service number is mentioned in the docs for the
     function in question. Ralf Brown's Interrupt List has all the details,
     if you are interested in looking them up. In order to call those
     services the library relies entirely on the extremely clever FT_Int86()
     function from the Nanforum Toolkit (written by Ted Means). 
     
     On the subject of LFN support, it should be said that using long file
     names on the command line in a DOS box is a completely separate thing
     from using long file names in DOS applications running on the same
     computer. The "DOS boxes", if I may use that term to refer to the
     command line of both CMD.EXE (on NT-class operating systems) and
     COMMAND.COM, are Win32 console applications which can handle long
     file names because they use the Win32 API.
     
     This does not necessarily mean that there is also support for the DOS
     LFN services, which are what we must use from inside a DOS application
     to get the same functionality. And unfortunately Microsoft "forgot" to
     add that kind of support in the NTVDM (the NT Virtual DOS Machine) on
     NT-versions prior to Windows 2000, so there is no official way to use
     the LFN Library in that environment. However, there is something called
     "The LFN Services for Windows NT 4.0" which claims to solve this
     problem, at least to some extent. Last time I looked, it was available
     for download at <http://www.cybertrails.com/~fys/longfile.htm>. I 
     should add that I have not tested that solution!
     
 Functions included in the LFN Library
     
     Long file name functions:
     LF_7143Supp()    Check if DOS function 7143h is supported
     LF_ChDir()       Change current directory to an LFN directory
     LF_CloseHand()   Close the FileFind handle after a file search
     LF_CurDir()      Get the current long file name directory
     LF_Directory()   Find all files that match a name pattern
     LF_Fcopy()       Copy a file with a long name to a new file
     LF_Fcreate()     Create a new file with a long file name
     LF_Ferase()      Erase a file with a long file name
     LF_Ferror()      Return the error code for an LFN operation
     LF_FindFirst()   Find the first file that matches a name pattern
     LF_FindNext()    Find the next file that matches a name pattern
     LF_Fopen()       Open an existing file with a long file name
     LF_Frename()     Rename a file
     LF_GetFAttr()    Get the attributes of a file
     LF_GetFInfo()    Get the date/time, (physical) size and attributes
                      of a file
     LF_GetFSize()    Get the physical size of a file (including slack)
     LF_GetFTime()    Get the creation time or last write or access time
                      of a file
     LF_GetHInfo()    Get the date/time, (real) size and attributes of a
                      file, based on a file handle
     LF_IsFile()      Determine if a file or a directory exists
     LF_LibVers()  *  Get the version number of the LFN Library
     LF_MkDir()       Create a directory with a long file name
     LF_RmDir()       Remove a directory with a long file name
     LF_SetFAttr()    Set the attributes of a file
     LF_SetFTime()    Set the creation time or last write or access time
                      of a file
     LF_Support()     Check if long file names are supported by the OS
     LF_ToLong()      Get the canonical long name for a short file name
     LF_ToShort()     Get the short name for a long file name or path
     LF_VolInfo()     Get volume info for a drive
     
     Demo application:
     LFNdemo()        A complete demo application
     
     The following functions are included in the Low Level Library (starting
     with Rev 1.00 of the LFN Library these functions have been moved to a
     separate library file).
     
     Low level functions:
     LL_FreeMem() *  Free a memory block allocated by LL_Str2Mem()
     LL_I2Attr()     Convert numerical file attributes to character
     LL_IsBitOn()    Check if a certain bit in an integer is on or off
     LL_Mem2Str()    Copy a string from memory to a char variable
     LL_LibVers() *  Get the version number of the Low Level Library
     LL_Offset()  *  Get the offset of a protected mode memory selector
     LL_Segment() *  Get the segment of a protected mode memory selector
     LL_Str2Mem() *  Copy a string to a static memory location
     
     New functions since the previous version are marked with an asterisk.
     Please note that the low level functions that were moved from the LFN
     Library to the Low Level Library were also renamed from LF_* to LL_*
     
     More info about the latest changes can be found in LFCHANGE.TXT
     
     It is recommended that you start by checking if the operating system
     supports the LFN-specific DOS services and avoid using them if that
     is not the case. The function to use for that test is LF_Support().
     In order to make your applications useful in both kinds of environments,
     you still have to provide support for "the old way" to handle files.
     
     If you intend to use any of the extended get/set attributes functions,
     it is recommended that you also call LF_7143Supp() to find out if the
     operating system supports those functions. That support follows its own
     rules in addition to requiring support for the LFN DOS services in
     general (a total mess, in my humble opinion). It is probably safer to
     use LF_GetHInfo() to retrieve that kind of information since the DOS
     service used by it seems to have more consistent support in various
     Windows versions.
     
     Although using most of the LFN Library functions only makes sense if
     the OS supports the LFN DOS services (for example, trying to create a
     file with a long name will definitely fail on "plain old DOS"), there
     are a few exceptions to that rule. LF_FindFirst(), LF_FindNext(),
     LF_Directory() and LF_IsFile() have support for both the LFN services
     and the corresponding SFN services that have been around since DOS 2.0,
     and they switch automatically between the two versions depending on the
     environment. This allows you to use the same routines to handle the
     result no matter which OS your application is running on.
     
 What has been fixed since the initial version?
     
     There is a lot of bit manipulation involved when retrieving file and
     directory information. File date, time, size and attributes are all
     encoded into bits, and sometimes they even span byte boundaries (for
     example, the hour component of a file time is located in bits 5-10
     in a word). This makes it a little complicated to calculate the data
     for a file. There are some bit handling functions in Clipper, and
     there are some in the Nanforum Toolkit. But some of them are written
     in Clipper code with the speed penalties that imposes, and the
     collection is not complete. I have deliberately NOT used any functions
     from Clipper Tools (if there are any) since not everyone owns that
     library.
     
     I have written a few additional file date/time specific bit manipulation
     routines to take care of what was missing in Clipper and Nanfor. In Rev
     0.90 they were written in Clipper and therefore not very fast. In Rev
     0.91 they were migrated from Clipper code to assembly, so they are now
     substantially faster than before.
     
     The names of the internal functions were also changed to reduce the risk
     of clashes with functions in other libraries. They now all start with
     "_lf".
     
     In Rev 0.92, there were no changes in the existing code. The only
     significant changes in the library since Rev 0.91 were the added
     functions that are mentioned in the "Change History" section of these
     docs and also briefly above.
     
     In Rev 1.00, the most important change is the reorganization of the
     library in two separate LIB files. This will require an update of your
     link script(s) and possibly some function name changes in your code (if
     you use any of the functions listed under "Low Level functions" above).
     
     Rev 1.00a adds a few new functions to the Low Level Library, but the
     LFN Library itself has not been changed.
     
 Possible problems
     
     I use Blinker, and I have personally only tested the LFN Library with
     version 5.1 of that linker. Other linkers may have problems with the LFN
     DOS services. Judging from what Ian Day says in one of his readme files,
     linking with Exospace could have been a potentional problem, but users
     of the LFN Library have reported that it works just fine with Exospace.
     
     It is also a fact that the support for the extended get/set attributes
     DOS services (getting and setting file date, time and attributes) varies
     between the different Windows versions with the older versions being the
     worst. See the docs for the individual functions for more info.
     
 What is needed in order to use the LFN Library?
     
     Well, obviously you need the library itself :-). And your normal 
     Clipper development tools, of course. If you do not use Clipper 5.2
     you will have to recompile the source code with your Clipper version.
     In that case you also need a library manager such as Microsoft's
     LIB.EXE unless you decide that you can live with linking the OBJ
     files separately into your applications.
     
     If you want to reassemble the assembly functions you also need MASM,
     the Microsoft Macro Assembler. I use version 5.1, but older versions
     should also work. I have tried version 6.1, but it is quite different
     from the earlier versions and may need changes in the source code. OBJ
     files for the assembly functions are included separately in case you
     do not have MASM but still want to rebuild the library from scratch.
     
     Starting with Rev 1.00, the library itself is split into two different
     lib files. The directly LFN related functions are in LFN.LIB as before,
     but the low level functions previously labeled "Companion Functions"
     have been moved to the new LL.LIB file and at the same time been renamed
     from LF_* to LL_*. You must supply both library names (LFN.LIB and
     LL.LIB) in your link script! Rev 1.00 of the LFN Library requires Rev
     1.00 or higher of the Low Level Library.
     
     You also need the Nanforum Toolkit and its companion CPMI library.
     If you do not have them already, you can download them from the Oasis
     <www.the-oasis.net>. CPMI.LIB is included in the Nanfor ZIP file.
     
     So in order to use the LFN Library, these are the four libraries that
     you must add to your link script: LFN, LL, NANFOR and CPMI
     
     If you need a Win32 Norton Guide viewer I can recommend Dave
     Pearson's WEG which you can download from his web site
     <www.davep.org/norton-guides/>.
     
     For recompiling the library source code, including the demo application,
     you also need the FTINT86.CH header file which comes with the Nanforum
     Toolkit, the LFNLIB.CH header file which is included in the LFN Library
     distribution and several standard Clipper header files.
     
     It is recommended that you use #defines from LFNLIB.CH in your own
     applications when making calls to LFN Library functions.
     
 Suggestions, bug reports etc
     
     I got a few suggestions for enhancements after the first two beta
     versions were released. They resulted in the added support for the
     extended get/set services, the file copy function and some changes in
     the docs.
     
     If you have any problems with the current version or any suggestions
     for making the library better, do not hesitate to tell me about them,
     either on comp.lang.clipper or via email at the address below.
     
     However, do not expect me to fix things overnight. This is free software,
     and you have the source code in the distribution. So if you are in a
     hurry to get something fixed, feel free to do it yourself for your own
     needs. But please let me know what you did so I can fix it in the next
     release for everyone's benefit.
     
 A word of caution
     
     The functions in the LFN library are low-level functions that allow
     you to create and delete files and directories and to overwrite
     existing files with new content.
     
     Since they allow low-level access to DOS files and devices they should
     be used with extreme care. They also require a thorough knowledge of
     the operating system. Incorrect use may cause irrepairable damage to
     the file system.
     
     I have tested with Clipper 5.2e and Blinker 5.1 and found that the
     functions work in both real and extended mode. I have not tested with
     any other linker, so it is possible that the DOS services called by
     the LFN library are not supported in all environments.
     
     There are known differences in the way that certain DOS services
     function between different Windows versions (some are reported in
     Ralf Brown's Interrupt List), which may cause some inconsistencies
     in the behavior of some of the LFN library functions. Windows NT4
     does not support long file names at all in the NTVDM (the NT Virtual
     DOS Machine), so there is no official way to use the LFN library in
     that environment.
     
     The extended get/set attributes functions are known to give very
     different results between different Windows versions, so you have
     to be careful when using them and preferably call LF_7143Supp() first
     to make sure that they work in your environment.
     
 Disclaimer
     
     Although I have checked everything thoroughly on my systems without
     problems, I cannot guarantee that the library functions will work
     correctly under all circumstances (please see the overview section
     for details on the current status). I will not take any responsi-
     bility for damage or loss of data incured whilst using the software.
     You use it entirely at your own risk. By using the software you agree
     to these terms.
     
     Enjoy,
     Klas
     
 Contact info
     
     Klas Engwall
     Engwall InfoTech AB
     email: klas.engwall@engwall.com
     